package com.example.aigc_education.integration.threeparty;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.aigc_education.common.BusinessException;
import com.example.aigc_education.constant.CacheConstants;
import com.example.aigc_education.constant.HttpStatus;
import com.example.aigc_education.domain.*;
import com.example.aigc_education.domain.dto.PaperQuestionsDTO;
import com.example.aigc_education.domain.dto.QuizQuestionDTO;
import com.example.aigc_education.domain.vo.GenCacheVO;
import com.example.aigc_education.enums.*;
import com.example.aigc_education.integration.emuns.CozeAsyncWorkflow;
import com.example.aigc_education.integration.emuns.CozeTaskStatus;
import com.example.aigc_education.integration.emuns.CozeWorkflowTypeV2;
import com.example.aigc_education.integration.processor.v1.CozeAsyncWFProcessor;
import com.example.aigc_education.integration.processor.v1.async.CozeAiTeacherAyncWFProcessor;
import com.example.aigc_education.integration.processor.v1.async.CozeAsyncPlanRequest;
import com.example.aigc_education.integration.processor.v1.sync.*;
import com.example.aigc_education.integration.processor.v2.async.GenFlashCardsAsyncProcessor;
import com.example.aigc_education.integration.processor.v2.async.GenQuizzesAsyncProcessor;
import com.example.aigc_education.integration.processor.v2.sync.GenFcSyncWFProcessor;
import com.example.aigc_education.integration.processor.v2.sync.GenQzSyncWFProcessor;
import com.example.aigc_education.integration.request.CozeRequest;
import com.example.aigc_education.integration.request.params.v1.CozeGenFlashCParam;
import com.example.aigc_education.integration.request.params.v1.CozeGenQuizzesParam;
import com.example.aigc_education.integration.request.params.v1.CozeStudyPlanParam;
import com.example.aigc_education.integration.request.params.v1.CozeWebSearchParam;
import com.example.aigc_education.integration.request.params.v2.CozeAiTeacherParam;
import com.example.aigc_education.integration.response.CozeAsyncResponse;
import com.example.aigc_education.integration.response.CozeResponse;
import com.example.aigc_education.integration.response.workflows.v1.*;
import com.example.aigc_education.mapper.*;
import com.example.aigc_education.utils.*;
import com.example.aigc_education.utils.UUID;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.SingletonMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CozeService {

    @Resource
    private CozeGenQzSyncWFProcessor cozeGenQzWFProcessor;

    @Resource
    private CozeGenFcSyncWFProcessor cozeGenFcSyncWFProcessor;

    @Resource
    private CozeStudyPlanSyncWFProcessor cozeStudyPlanWFProcessor;

    @Resource
    private CozeWebSearchSyncWFProcessor cozeWebSearchWFProcessor;

    @Resource
    private GenQzSyncWFProcessor genQzSyncWFProcessor;

    @Resource
    private GenFcSyncWFProcessor genFcSyncWFProcessor;

    @Resource
    private GenQuizzesAsyncProcessor genQuizzesAsyncProcessor;

    @Resource
    private GenFlashCardsAsyncProcessor genFcAsyncWFProcessor;

    @Resource
    private CozeTaskMapper cozeTaskMapper;

    @Resource
    private ThemeMapper themeMapper;

    @Resource
    private PlanMapper planMapper;

    @Resource
    private ResourcesMapper resourcesMapper;

    @Resource
    private PaperMapper paperMapper;

    @Resource
    private ChatHistoryMapper chatHistoryMapper;

    @Resource
    private PlatformTransactionManager transactionManager;

    @Resource
    private List<CozeAsyncWFProcessor> cozeAsyncWFProcessorList;

    @Autowired
    private RedisCache redisCache;

    @Resource
    private CozeAiTeacherSyncWFProcessor aiTeacherSyncWFProcessor;

    private final Map<CozeAsyncWorkflow, CozeAsyncWFProcessor> cozeAsyncWFProcessorMap = new HashMap<>();
    @Resource
    private CozeAiTeacherAyncWFProcessor cozeAiTeacherAyncWFProcessor;

    @PostConstruct
    public void buildAsyncChain(){
        cozeAsyncWFProcessorList.forEach(processor -> {
            cozeAsyncWFProcessorMap.put(processor.workflowType(), processor);
        });
    }

    // 得到生成抽认卡和生成计划的链
    public List<CozeAsyncWorkflow> getStudyPlanChain(){
        return Arrays.asList(
                CozeAsyncWorkflow.GEN_FC,
                CozeAsyncWorkflow.GEN_QZ,
                CozeAsyncWorkflow.WEB_SEARCH
        );
    }

    private final ExecutorService executorService = new ThreadPoolExecutor(
            2,                      // 核心线程数
            4,                    // 最大线程数
            60L,                   // 空闲线程存活时间
            TimeUnit.SECONDS,      // 时间单位
            new LinkedBlockingQueue<>(50),  // 任务队列
            new ThreadFactoryBuilder()
                    .setNameFormat("study-plan-generator-%d")
                    .build(),      // 线程工厂
            new ThreadPoolExecutor.CallerRunsPolicy()  // 拒绝策略
    );

    /**
     * 生成计划的流程
     * 生成计划 -> 生成试题
     *        -> 生成抽认卡   ====> 存入数据库
     *        -> AI资源搜索
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil genStudyPlan(Long userId, String title, String subject, String grade, String goal, String language){
        log.info("CozeService genStudyPlan userId:{},subject:{},grade:{},goal:{},language:{}", userId, subject, grade, goal, language);

        Plan plan = new Plan();
        plan.setPlanName(title);
        plan.setThemeTitle(subject);
        plan.setUserLearningStage(grade);
        plan.setDesiredLevel(goal);
        plan.setUserId(userId);
        int insert = planMapper.insert(plan);
        if(insert == 0){
            throw new BusinessException("生成计划失败");
        }

        // 生成计划 算法调用
        CompletableFuture.runAsync(() -> {
            TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
            transactionTemplate.execute(status -> {
                try {
                    // 生成计划的逻辑...
                    CozeStudyPlanParam studyPlanParam = CozeStudyPlanParam.builder()
                            .subject(subject)
                            .grade(grade)
                            .goal(goal)
                            .language(language)
                            .build();
                    CozeRequest<CozeStudyPlanParam> studyPlanParamCozeRequest = new CozeRequest<CozeStudyPlanParam>();
                    studyPlanParamCozeRequest.setParameters(studyPlanParam);
                    CozeStudyPlanResponse studyPlan = Optional.ofNullable(cozeStudyPlanWFProcessor.runWorkFlow(studyPlanParamCozeRequest, CozeStudyPlanResponse.class))
                            .orElseThrow(() -> new BusinessException("生成计划失败"));

                    CozeStudyPlanResponse.StudyPlanData studyPlanData = Optional.ofNullable(studyPlan.getData())
                            .orElseThrow(() -> new BusinessException("生成计划失败"));
                    // 保存计划目录到DB中，返回theme_id 操作一下流程
                    studyPlanData.getPlan().forEach(themes -> {
                        Theme theme = new Theme();
                        theme.setThemeTitle(themes.getTopic());
                        theme.setPlanId(plan.getPlanId());
                        themeMapper.insert(theme);
                        themes.getSubtopics().forEach(subtopic -> {
                            Theme subTheme = new Theme();
                            subTheme.setThemeTitle(subtopic);
                            subTheme.setSuperiorThemeId(theme.getThemeId());
                            subTheme.setPlanId(plan.getPlanId());
                            themeMapper.insert(subTheme);
                            // 将计划的topic与subtopics，组成CozeAsyncPlanRequest对象,遍历subtopic与theme_id,
                            getStudyPlanChain().forEach(cozeAsyncWorkflow -> {
                                CozeAsyncPlanRequest request = CozeAsyncPlanRequest
                                        .builder()
                                        .topic(themes.getTopic())
                                        .subtopic(subtopic)
                                        .build();
                                CozeResponse response = cozeAsyncWFProcessorMap.get(cozeAsyncWorkflow)
                                        .asyncRunWorkFlow(request);
                                log.info("CozeService genStudyPlan coze_{},response:{}", cozeAsyncWorkflow.getName(), response);
                                // 将任务名，状态、executeId逐个存入DB中
                                CozeTask cozeTask = new CozeTask();
                                cozeTask.setThemeId(subTheme.getThemeId());
                                cozeTask.setPlanId(plan.getPlanId());
                                cozeTask.setTaskName(String.format("coze_task_%s_%s_%s", themes.getTopic(), subtopic, UUID.fastUUID()));
                                cozeTask.setExecuteId(response.getExecuteId());
                                cozeTask.setWorkflowId(cozeAsyncWorkflow.getWorkflowId());
                                cozeTask.setInput(JsonUtils.toJson(request));
                                cozeTask.setTaskStatus(CozeTaskStatus.RUNNING.getValue());
                                cozeTask.setTaskType(cozeAsyncWorkflow.getValue());
                                cozeTaskMapper.insert(cozeTask);
                            });
                        });
                    });
                } catch (Exception e) {
                    log.error("生成学习计划失败", e);
                    status.setRollbackOnly();
                    planMapper.updateById(plan);
                    return null;
                }
                return null;
            });
        }, executorService);

        // 返回给计划Id
        return ResultUtil.success("正在生成计划，请稍后查看",new SingletonMap("planId", plan.getPlanId()));
    }

    @Resource
    private UserMapper userMapper;
    /**
     * 生成抽认卡的流程
     * 生成抽认卡 -> 生成试题
     *        -> AI资源搜索

    /**
     * 生成计划的流程
     * 生成计划 -> 生成试题
     *        -> 生成抽认卡   ====> 存入数据库
     *        -> AI资源搜索
     */
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil genStudyPlanV2(User loginUser, String title, String subject, String stage, String targetLevel, String priority, String coverUrl) {
        log.info("CozeService genStudyPlan user:{},subject:{},stage:{},targetLevel:{},priority:{},coverUrl:{}", JsonUtils.toJson(loginUser), subject, stage, targetLevel, priority,coverUrl);

        Plan plan = new Plan();
        plan.setPlanName(title);
        plan.setThemeTitle(subject);
        plan.setUserLearningStage(stage);
        plan.setDesiredLevel(targetLevel);
        plan.setPriority(PlanPriorityType.fromTitle(priority).getValue());
        plan.setCoverImg(coverUrl);
        plan.setUserId(loginUser.getUserId());
        int insert = planMapper.insert(plan);
        if(insert == 0){
            throw new BusinessException("生成计划失败");
        }

        // 生成计划 算法调用
        CompletableFuture.runAsync(() -> {
            TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
            transactionTemplate.execute(status -> {
                try {
                    // 生成计划的逻辑...
                    CozeStudyPlanParam studyPlanParam = CozeStudyPlanParam.builder()
                            .subject(subject)
                            .grade(stage)
                            .goal(targetLevel)
                            .language("中文")
                            .build();
                    CozeRequest<CozeStudyPlanParam> studyPlanParamCozeRequest = new CozeRequest<CozeStudyPlanParam>();
                    studyPlanParamCozeRequest.setParameters(studyPlanParam);
                    CozeStudyPlanResponse studyPlan = Optional.ofNullable(cozeStudyPlanWFProcessor.runWorkFlow(studyPlanParamCozeRequest, CozeStudyPlanResponse.class))
                            .orElseThrow(() -> new BusinessException("生成计划失败"));

                    CozeStudyPlanResponse.StudyPlanData studyPlanData = Optional.ofNullable(studyPlan.getData())
                            .orElseThrow(() -> new BusinessException("生成计划失败"));
                    // 保存计划目录到DB中，返回theme_id 操作一下流程
                    studyPlanData.getPlan().forEach(themes -> {
                        Theme theme = new Theme();
                        theme.setThemeTitle(themes.getTopic());
                        theme.setPlanId(plan.getPlanId());
                        themeMapper.insert(theme);

                        // ai导师提示词
                        CozeAsyncPlanRequest aiTeacherRequest = CozeAsyncPlanRequest
                               .builder()
                               .topic(themes.getTopic())
                               .subtopic(themes.getSubtopics().toString())
                                .build();
                        CozeResponse aiResponse = Optional.ofNullable(cozeAiTeacherAyncWFProcessor.executeWorkFlow(aiTeacherRequest, loginUser, targetLevel))
                                .orElseThrow(() -> new BusinessException("AI导师生成失败"));

                        log.info("CozeService AI_TEACHER coze_{},response:{}", CozeAsyncWorkflow.AI_TEACHER.getName(), aiResponse);

                        // 将任务名，状态、executeId逐个存入DB中
                        CozeTask aiTeacherCozeTask = new CozeTask();
                        aiTeacherCozeTask.setThemeId(theme.getThemeId());
                        aiTeacherCozeTask.setPlanId(plan.getPlanId());
                        aiTeacherCozeTask.setTaskName(String.format("coze_task_%s_%s_%s", themes.getTopic(), themes.getSubtopics().toString(), UUID.fastUUID()));
                        aiTeacherCozeTask.setExecuteId(aiResponse.getExecuteId());
                        aiTeacherCozeTask.setWorkflowId(CozeAsyncWorkflow.AI_TEACHER.getWorkflowId());
                        aiTeacherCozeTask.setInput(JsonUtils.toJson(aiTeacherRequest));
                        aiTeacherCozeTask.setTaskStatus(CozeTaskStatus.RUNNING.getValue());
                        aiTeacherCozeTask.setTaskType(CozeAsyncWorkflow.AI_TEACHER.getValue());
                        cozeTaskMapper.insert(aiTeacherCozeTask);



                        themes.getSubtopics().forEach(subtopic -> {
                            Theme subTheme = new Theme();
                            subTheme.setThemeTitle(subtopic);
                            subTheme.setSuperiorThemeId(theme.getThemeId());
                            subTheme.setPlanId(plan.getPlanId());
                            themeMapper.insert(subTheme);
                            // 将计划的topic与subtopics，组成CozeAsyncPlanRequest对象,遍历subtopic与theme_id,
                            getStudyPlanChain().forEach(cozeAsyncWorkflow -> {
                                CozeAsyncPlanRequest request = CozeAsyncPlanRequest
                                        .builder()
                                        .topic(themes.getTopic())
                                        .subtopic(subtopic)
                                        .build();
                                CozeResponse response = cozeAsyncWFProcessorMap.get(cozeAsyncWorkflow)
                                        .asyncRunWorkFlow(request);
                                log.info("CozeService genStudyPlan coze_{},response:{}", cozeAsyncWorkflow.getName(), response);
                                // 将任务名，状态、executeId逐个存入DB中
                                CozeTask cozeTask = new CozeTask();
                                cozeTask.setThemeId(subTheme.getThemeId());
                                cozeTask.setPlanId(plan.getPlanId());
                                cozeTask.setTaskName(String.format("coze_task_%s_%s_%s", themes.getTopic(), subtopic, UUID.fastUUID()));
                                cozeTask.setExecuteId(response.getExecuteId());
                                cozeTask.setWorkflowId(cozeAsyncWorkflow.getWorkflowId());
                                cozeTask.setInput(JsonUtils.toJson(request));
                                cozeTask.setTaskStatus(CozeTaskStatus.RUNNING.getValue());
                                cozeTask.setTaskType(cozeAsyncWorkflow.getValue());
                                cozeTaskMapper.insert(cozeTask);
                            });
                        });
                    });
                } catch (Exception e) {
                    log.error("生成学习计划失败", e.getMessage());
                    status.setRollbackOnly();
                    planMapper.updateById(plan);
                    return null;
                }
                return null;
            });
        }, executorService);

        // 返回给计划Id
        return ResultUtil.success("正在生成计划，请稍后查看",new SingletonMap("planId", plan.getPlanId()));
    }

    /**
     * 定时查询异步任务执行情况
     */
    @Transactional
    public void queryAsyncTaskResult(Long planId){
        List<Theme> themes = Optional.ofNullable(themeMapper.selectList(new LambdaQueryWrapper<Theme>().eq(Theme::getPlanId, planId).eq(Theme::getSuperiorThemeId, 0)))
                .orElseThrow(() -> new BusinessException("计划不存在"));

        themes.forEach(theme -> {

            /**
             * 二级主题 -->
             * 生成ai导师提示词
             */
            CozeTask aiTeacherCozeTask = cozeTaskMapper.selectOne(new LambdaQueryWrapper<CozeTask>().eq(CozeTask::getThemeId, theme.getThemeId()).eq(CozeTask::getTaskStatus, CozeTaskStatus.RUNNING.getValue()));

            if (Objects.nonNull(aiTeacherCozeTask)) {
                // 判断ExecuteId是否存在
                if(aiTeacherCozeTask.getExecuteId() == null){
                    aiTeacherCozeTask.setTaskStatus(CozeTaskStatus.FAIL.getValue());
                    cozeTaskMapper.updateById(aiTeacherCozeTask);
                }else {
                    // 调用coze查询任务接口判断是否完成
                    CozeAsyncResponse response = cozeAsyncWFProcessorMap.get(CozeAsyncWorkflow.fromValue(aiTeacherCozeTask.getTaskType()))
                            .queryTaskStatus(aiTeacherCozeTask.getWorkflowId(), aiTeacherCozeTask.getExecuteId());

                    // 完成则更新任务状态并更新数据到数据库
                    if(response.getData().get(0).getExecuteStatus().equals("Success")) {
                        aiTeacherCozeTask.setTaskStatus(CozeTaskStatus.SUCCESS.getValue());
                        aiTeacherCozeTask.setOutput(JsonUtils.toJson(response.getData()));
                        cozeTaskMapper.updateById(aiTeacherCozeTask);

                        // 插入到数据到各个实体表中
                        String output = Optional.ofNullable(response.getData().get(0).getOutput())
                                .orElseThrow(() -> new BusinessException("算法生成结果失败"));
                        String data = Optional.ofNullable(JSONObject.parseObject(output).getString("Output"))
                                .orElseThrow(() -> new BusinessException("算法无输出结果"));

                        if (aiTeacherCozeTask.getTaskType().equals(CozeAsyncWorkflow.AI_TEACHER.getValue())) {
                            CozeAiTeacherResponse aiTeacher = Optional.ofNullable(JsonUtils.fromJson(data, CozeAiTeacherResponse.class))
                                    .orElseThrow(() -> new BusinessException("AI导师解析失败"));
                            log.info("CozeService queryAsyncTaskResult theme_name:{},subtheme_name:{},aiTeacher:{}", theme.getThemeTitle(), theme.getThemeTitle(), JsonUtils.toJson(aiTeacher));

                            ChatHistory chatHistory = new ChatHistory();
                            chatHistory.setBotId(theme.getThemeId());
                            chatHistory.setContent(aiTeacher.getOutput());
                            chatHistory.setRole(ChatHistoryType.SYSTEM.getTitle());
                            chatHistoryMapper.insert(chatHistory);
                        }else {
                            throw new BusinessException("任务类型错误");
                        }

                    } else if (response.getData().get(0).getExecuteStatus().equals("Fail")){
                        log.info("CozeService queryAsyncTaskResult theme_name:{},subtheme_name:{},task fail", theme.getThemeTitle(), theme.getThemeTitle());
                        aiTeacherCozeTask.setTaskStatus(CozeTaskStatus.FAIL.getValue());
                        cozeTaskMapper.updateById(aiTeacherCozeTask);
                    }
                }
            }


            List<Theme> subThemes = Optional.ofNullable(themeMapper.selectList(new LambdaQueryWrapper<Theme>().eq(Theme::getSuperiorThemeId, theme.getThemeId())))
                    .orElseThrow(() -> new BusinessException("计划不存在"));
            subThemes.forEach(subTheme -> {
                // 过滤出running的任务,如果cozeTasks为空则跳出循环
                List<CozeTask> cozeTasks = Optional.ofNullable(cozeTaskMapper.selectList(new LambdaQueryWrapper<CozeTask>().eq(CozeTask::getThemeId, subTheme.getThemeId()).eq(CozeTask::getTaskStatus, CozeTaskStatus.RUNNING.getValue())))
                        .orElseThrow(() -> new BusinessException("计划不存在"));
                cozeTasks.forEach(cozeTask -> {
                    // 判断ExecuteId是否存在
                    if(cozeTask.getExecuteId() == null){
                        cozeTask.setTaskStatus(CozeTaskStatus.FAIL.getValue());
                        cozeTaskMapper.updateById(cozeTask);
                    } else {
                        // 调用coze查询任务接口判断是否完成
                        CozeAsyncResponse response = cozeAsyncWFProcessorMap.get(CozeAsyncWorkflow.fromValue(cozeTask.getTaskType()))
                                .queryTaskStatus(cozeTask.getWorkflowId(), cozeTask.getExecuteId());
                        // 完成则更新任务状态并更新数据到数据库
                        if(response.getData().get(0).getExecuteStatus().equals("Success")){
                            cozeTask.setTaskStatus(CozeTaskStatus.SUCCESS.getValue());
                            cozeTask.setOutput(JsonUtils.toJson(response.getData()));
                            // todo：是否可以做优化
                            cozeTaskMapper.updateById(cozeTask);
                            // 插入到数据到各个实体表中
                            String output = Optional.ofNullable(response.getData().get(0).getOutput())
                                    .orElseThrow(() -> new BusinessException("算法生成结果失败"));
                            String data = Optional.ofNullable(JSONObject.parseObject(output).getString("Output"))
                                    .orElseThrow(() -> new BusinessException("算法无输出结果"));

                            if(cozeTask.getTaskType().equals(CozeAsyncWorkflow.GEN_FC.getValue())){
                                CozeGenFlashCResponse genFlashC = Optional.ofNullable(JsonUtils.fromJson(data, CozeGenFlashCResponse.class))
                                        .orElseThrow(() -> new BusinessException("生成抽认卡解析失败"));
                                // 生成抽认卡
                                Paper paper = new Paper();
                                // 今天的日期 yyyy-MM-dd
                                paper.setPaperName(String.format("%s_%s", subTheme.getThemeTitle(), LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))));
                                paper.setDifficulty(PaperDifficultyType.EASY.getValue());
                                paper.setThemeId(subTheme.getThemeId());
                                paper.setPaperType(PaperUseType.FLASHCARD.getValue());
                                paper.setLanguage(LanguageType.CHINESE.getValue());
                                paper.setAnswerStatus(UserAnswerStatus.FLASHCARD_STATUS.getStatus());
                                paper.setQuestionNum(genFlashC.getData().size());
                                List<PaperQuestionsDTO> paperQuestions = new ArrayList<>();
                                for (int i = 0; i < genFlashC.getData().size(); i++) {
                                    PaperQuestionsDTO questionsDTO = new PaperQuestionsDTO();
                                    questionsDTO.setQuestionNo(i + 1);
                                    questionsDTO.setContent(genFlashC.getData().get(i).getCardQuestion());
                                    questionsDTO.setAnswerDescription(genFlashC.getData().get(i).getCardAnswer());
                                    questionsDTO.setAnswerStatus(AnswerStatus.INIT.getValue());
                                    paperQuestions.add(questionsDTO);
                                }
                                paper.setQuestions(JsonUtils.toJson(paperQuestions));
                                // todo:for循环里面的插入操作，是否可以优化
                                paperMapper.insert(paper);
                                log.info("CozeService queryAsyncTaskResult theme_name:{},subtheme_name:{},genFlashC:{}", theme.getThemeTitle(), subTheme.getThemeTitle(), JsonUtils.toJson(genFlashC));
                            }else if(cozeTask.getTaskType().equals(CozeAsyncWorkflow.GEN_QZ.getValue())){
                                CozeGenQuizzesResponse genQuizzes = Optional.ofNullable(JsonUtils.fromJson(data, CozeGenQuizzesResponse.class))
                                        .orElseThrow(() -> new BusinessException("生成试题解析失败"));
                                // 生成试题
                                Paper paper = new Paper();
                                // 今天的日期 yyyy-MM-dd
                                paper.setPaperName(String.format("%s_%s", subTheme.getThemeTitle(), LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))));
                                paper.setDifficulty(PaperDifficultyType.EASY.getValue());
                                paper.setThemeId(subTheme.getThemeId());
                                paper.setPaperType(PaperUseType.EXAM.getValue());
                                paper.setLanguage(LanguageType.CHINESE.getValue());
                                paper.setAnswerStatus(UserAnswerStatus.QUIZZES_STATUS.getStatus());
                                paper.setQuestionNum(genQuizzes.getData().size());

//                                List<PaperQuestionsDTO> paperQuestions = new ArrayList<>();
//                                for (int i = 0; i < genQuizzes.getData().size(); i++) {
//                                    PaperQuestionsDTO questionsDTO = new PaperQuestionsDTO();
//                                    questionsDTO.setQuestionNo(i + 1);
//                                    questionsDTO.setContent(genQuizzes.getData().get(i).getQuestion());
//                                    questionsDTO.setCorrectAnswer(genQuizzes.getData().get(i).getAnswer());
//                                    questionsDTO.setAnswerDescription(genQuizzes.getData().get(i).getExplanation());
//                                    questionsDTO.setOptions(genQuizzes.getData().get(i).getOptions());
//                                    questionsDTO.setUserAnswer("");
//                                    questionsDTO.setLastAnswer("");
//                                    questionsDTO.setAnswerStatus(AnswerStatus.INIT.getValue());
//                                    paperQuestions.add(questionsDTO);
//                                }
//                                paper.setQuestions(JsonUtils.toJson(paperQuestions));

                                //添加试卷里的问题集合逻辑
                                List<QuizQuestionDTO> questionDTOs =  new ArrayList<>();
                                Integer questionNO = 1;
                                for (CozeGenQuizzesResponse.QuizzesData quiz : genQuizzes.getData()) {
                                    QuizQuestionDTO quizQuestionDTO = BeanUtil.copyProperties(quiz, QuizQuestionDTO.class);
                                    quizQuestionDTO.setQuestionNo(questionNO);
                                    questionNO++;
                                    quizQuestionDTO.setAnswer(Collections.singletonList(quiz.getAnswer()));
                                    quizQuestionDTO.setAnswerStatus((short) AnswerStatus.INIT.getValue());
                                    quizQuestionDTO.setOptions(JSON.toJSONString(quiz.getOptions()));
                                    quizQuestionDTO.setQuestionType("single");
                                    //设为空集合
                                    quizQuestionDTO.setUserAnswer(new ArrayList<>());
                                    quizQuestionDTO.setLastAnswer(new ArrayList<>());
                                    questionDTOs.add(quizQuestionDTO);
                                }
                                paper.setQuestions(JSON.toJSONString(questionDTOs));

                                // todo:for循环里面的插入操作，是否可以优化
                                paperMapper.insert(paper);
                                log.info("CozeService queryAsyncTaskResult theme_name:{},subtheme_name:{},genQuizzes:{}", theme.getThemeTitle(), subTheme.getThemeTitle(), JsonUtils.toJson(genQuizzes));
                            } else if(cozeTask.getTaskType().equals(CozeAsyncWorkflow.WEB_SEARCH.getValue())) {
                                CozeWebSearchResponse webSearch = Optional.ofNullable(JsonUtils.fromJson(data, CozeWebSearchResponse.class))
                                        .orElseThrow(() -> new BusinessException("网络资源解析失败"));
                                log.info("CozeService queryAsyncTaskResult theme_name:{},subtheme_name:{},webSearch:{}", theme.getThemeTitle(), subTheme.getThemeTitle(), JsonUtils.toJson(webSearch));
                                // AI资源搜索
                                Resources resources = new Resources();
                                resources.setThemeId(subTheme.getThemeId());
                                resources.setSummary(webSearch.getData().getSummary());
                                resources.setLearningLink(JsonUtils.toJson(webSearch.getData().getUrls()));
                                // todo:for循环里面的插入操作，是否可以优化 做批量
                                resourcesMapper.insert(resources);
                            }
                            else {
                                throw new BusinessException("任务类型错误");
                            }
                        }else if (response.getData().get(0).getExecuteStatus().equals("Fail")){
                            log.info("CozeService queryAsyncTaskResult theme_name:{},subtheme_name:{},task fail", theme.getThemeTitle(), subTheme.getThemeTitle());
                            cozeTask.setTaskStatus(CozeTaskStatus.FAIL.getValue());
                            cozeTaskMapper.updateById(cozeTask);
                        }
                    }
                });
            });
        });
    }


    /**
     * 生成试题
     */
    public ResultUtil genQuizzes(String topic, String subtopic, String quizzesNum, String difficulty){
        CozeGenQuizzesParam param = new CozeGenQuizzesParam();
        param.setTopic(topic);
        param.setSubtopic(subtopic);
        param.setQuestionNum(quizzesNum);
        param.setDifficulty(difficulty);
        CozeRequest<CozeGenQuizzesParam> cozeRequest = new CozeRequest<>();
        cozeRequest.setParameters(param);
        log.info("CozeService genQuizzes request:{}", JsonUtils.toJson(cozeRequest));
        CozeGenQuizzesResponse response = Optional.ofNullable(cozeGenQzWFProcessor.runWorkFlow(cozeRequest, CozeGenQuizzesResponse.class))
                .orElseThrow(() -> new BusinessException("生成试题失败"));
        log.info("CozeService genQuizzes response:{}", JsonUtils.toJson(response));
        return ResultUtil.success("AI生成测验成功",response.getData());
    }

    /**
     * 生成试题V2
     * 三种模式：主题与子主题、文件模式，外部链接模式
     * 主题与子主题：必须传入topic与subtopic
     * 文件模式：url传入oss的url, urlType传file，filename传文件名
     * 外部链接模式：url传入外部链接，urlType传link
     * todo: 垃圾代码需要优化，枚举判断等
     */
    public ResultUtil genQuizzesV2( String topic, String subtopic, String questionNum, String difficulty, String questionType, String url, String urlType, String filename) {
        com.example.aigc_education.integration.request.params.v2.CozeGenQuizzesParam param = new com.example.aigc_education.integration.request.params.v2.CozeGenQuizzesParam();
        if ("file".equals(urlType)) {
            param.setUrl(url);
            param.setUrlType(urlType);
            param.setFilename(filename);
        } else if ("link".equals(urlType)) {
            param.setUrl(url);
            param.setUrlType(urlType);
        } else {
            param.setTopic(topic);
            param.setSubtopic(subtopic);
        }
        param.setQuestionNum(questionNum);
        param.setDifficulty(difficulty);
        param.setQuestionType(questionType);
        CozeRequest<com.example.aigc_education.integration.request.params.v2.CozeGenQuizzesParam> cozeRequest = new CozeRequest<>();
        cozeRequest.setParameters(param);
        log.info("CozeService genQuizzesV2 request:{}", JsonUtils.toJson(cozeRequest));
        com.example.aigc_education.integration.response.workflows.v2.CozeGenQuizzesResponse response = Optional.ofNullable(genQzSyncWFProcessor.execute(cozeRequest, com.example.aigc_education.integration.response.workflows.v2.CozeGenQuizzesResponse.class))
                .orElseThrow(() -> new BusinessException("生成试题失败"));
        log.info("CozeService genQuizzesV2 response:{}", JsonUtils.toJson(response));
        return ResultUtil.success("AI生成测验成功", response.getQuestions());
    }

    /**
     * 生成试题V2(异步调用)
     * 三种模式：主题与子主题、文件模式，外部链接模式
     * 主题与子主题：必须传入topic与subtopic
     * 文件模式：url传入oss的url, urlType传file，filename传文件名
     * 外部链接模式：url传入外部链接，urlType传link
     * todo: 垃圾代码需要优化，枚举判断等
     */
    public ResultUtil asyncGenQuizzesV2( String topic, String subtopic, String questionNum, String difficulty, String questionType, String url, String urlType, String filename) {
        com.example.aigc_education.integration.request.params.v2.CozeGenQuizzesParam param = new com.example.aigc_education.integration.request.params.v2.CozeGenQuizzesParam();
        if ("file".equals(urlType)) {
            param.setUrl(url);
            param.setUrlType(urlType);
            param.setFilename(filename);
        } else if ("link".equals(urlType)) {
            param.setUrl(url);
            param.setUrlType(urlType);
        } else {
            param.setTopic(topic);
            param.setSubtopic(subtopic);
        }
        param.setQuestionNum(questionNum);
        param.setDifficulty(difficulty);
        param.setQuestionType(questionType);
        CozeRequest<com.example.aigc_education.integration.request.params.v2.CozeGenQuizzesParam> cozeRequest = new CozeRequest<>();
        cozeRequest.setParameters(param);
        log.info("CozeService genQuizzesV2 request:{}", JsonUtils.toJson(cozeRequest));
        CozeResponse response = Optional.ofNullable(genQuizzesAsyncProcessor.execute(cozeRequest))
                .orElseThrow(() -> new BusinessException("生成试题失败"));
        return ResultUtil.success("AI生成测验使用成功", new SingletonMap("executeId", response.getExecuteId()));
    }

    /**
     * 生成抽认卡V2
     * 三种模式：主题与子主题、文件模式，外部链接模式
     * 主题与子主题：必须传入topic与subtopic
     * 文件模式：url传入oss的url, urlType传file，filename传文件名
     * 外部链接模式：url传入外部链接，urlType传link
     * todo: 垃圾代码需要优化，枚举判断等
     */
    public ResultUtil asyncGenFlashcardsV2(String topic, String subtopic, String flashcardsNum, String difficulty, String url, String urlType, String filename) {
        com.example.aigc_education.integration.request.params.v2.CozeGenFlashCParam param = new com.example.aigc_education.integration.request.params.v2.CozeGenFlashCParam();
        if ("file".equals(urlType)) {
            param.setUrl(url);
            param.setUrlType(urlType);
            param.setFilename(filename);
        } else if ("link".equals(urlType)) {
            param.setUrl(url);
            param.setUrlType(urlType);
        } else {
            param.setTopic(topic);
            param.setSubtopic(subtopic);
        }
        param.setCardNum(flashcardsNum);
        param.setDifficulty(difficulty);
        CozeRequest<com.example.aigc_education.integration.request.params.v2.CozeGenFlashCParam> cozeRequest = new CozeRequest<>();
        cozeRequest.setParameters(param);
        log.info("CozeService genFlashcardsV2 request:{}", JsonUtils.toJson(cozeRequest));
        CozeResponse response = Optional.ofNullable(genFcAsyncWFProcessor.execute(cozeRequest))
                .orElseThrow(() -> new BusinessException("生成抽认卡失败"));
        log.info("CozeService genFlashcardsV2 response:{}", JsonUtils.toJson(response));
        return ResultUtil.success("AI生成抽认卡成功", new SingletonMap("executeId", response.getExecuteId()));
    }


    /**
     * 垃圾代码，切勿模仿
     * @param executeId
     * @param taskType
     * @return
     */
    public ResultUtil queryAITaskStatus(String executeId, String taskType) {
        if (CozeAsyncWorkflow.GEN_QZ.getValue().equals(taskType)) {
            CozeAsyncResponse response = genQuizzesAsyncProcessor.queryTaskStatus(executeId);
            if("Running".equals(response.getData().get(0).getExecuteStatus())) {
                return ResultUtil.success("查询任务状态成功", new SingletonMap("status", "Running"));
            } else if ("Fail".equals(response.getData().get(0).getExecuteStatus())) {
                return ResultUtil.success("查询任务状态成功", new SingletonMap("status", "Fail"));
            } else {
                return ResultUtil.success("查询任务状态成功", JsonUtils.fromJson(response.getData().get(0).getOutput(), com.example.aigc_education.integration.response.workflows.v2.CozeGenQuizzesResponse.class));
            }
        } else if (CozeAsyncWorkflow.GEN_FC.getValue().equals(taskType)) {
            CozeAsyncResponse response = genFcAsyncWFProcessor.queryTaskStatus(executeId);
            if("Running".equals(response.getData().get(0).getExecuteStatus())) {
                return ResultUtil.success("查询任务状态成功", new SingletonMap("status", "Running"));
            } else if ("Fail".equals(response.getData().get(0).getExecuteStatus())) {
                return ResultUtil.success("查询任务状态成功", new SingletonMap("status", "Fail"));
            } else {
                return ResultUtil.success("查询任务状态成功", JsonUtils.fromJson(response.getData().get(0).getOutput(), com.example.aigc_education.integration.response.workflows.v2.CozeGenFlashCResponse.class));
            }
        } else {
            throw new BusinessException("任务类型错误");
        }
    }

    /**
     * 生成抽认卡
     */
    public ResultUtil genFlashcards(String topic, String subtopic, String flashcardsNum, String difficulty) {
        CozeGenFlashCParam param = new CozeGenFlashCParam();
        param.setTopic(topic);
        param.setSubtopic(subtopic);
        param.setCardNum(flashcardsNum);
        param.setDifficulty(difficulty);
        CozeRequest<CozeGenFlashCParam> cozeRequest = new CozeRequest<>();
        cozeRequest.setParameters(param);
        log.info("CozeService genFlashcards request:{}", JsonUtils.toJson(cozeRequest));
        CozeGenFlashCResponse response = Optional.ofNullable(cozeGenFcSyncWFProcessor.runWorkFlow(cozeRequest, CozeGenFlashCResponse.class))
                .orElseThrow(() -> new BusinessException("生成抽认卡失败"));
        log.info("CozeService genFlashcards response:{}", JsonUtils.toJson(response));
        return ResultUtil.success("AI生成抽认卡成功", response.getData());
    }

    /**
     * 生成抽认卡V2
     * 三种模式：主题与子主题、文件模式，外部链接模式
     * 主题与子主题：必须传入topic与subtopic
     * 文件模式：url传入oss的url, urlType传file，filename传文件名
     * 外部链接模式：url传入外部链接，urlType传link
     * todo: 垃圾代码需要优化，枚举判断等
     */
    public ResultUtil genFlashcardsV2(String topic, String subtopic, String flashcardsNum, String difficulty, String url, String urlType, String filename) {
        com.example.aigc_education.integration.request.params.v2.CozeGenFlashCParam param = new com.example.aigc_education.integration.request.params.v2.CozeGenFlashCParam();
        if ("file".equals(urlType)) {
            param.setUrl(url);
            param.setUrlType(urlType);
            param.setFilename(filename);
        } else if ("link".equals(urlType)) {
            param.setUrl(url);
            param.setUrlType(urlType);
        } else {
            param.setTopic(topic);
            param.setSubtopic(subtopic);
        }
        param.setCardNum(flashcardsNum);
        param.setDifficulty(difficulty);
        CozeRequest<com.example.aigc_education.integration.request.params.v2.CozeGenFlashCParam> cozeRequest = new CozeRequest<>();
        cozeRequest.setParameters(param);
        log.info("CozeService genFlashcardsV2 request:{}", JsonUtils.toJson(cozeRequest));
        com.example.aigc_education.integration.response.workflows.v2.CozeGenFlashCResponse response = Optional.ofNullable(genFcSyncWFProcessor.execute(cozeRequest, com.example.aigc_education.integration.response.workflows.v2.CozeGenFlashCResponse.class))
                .orElseThrow(() -> new BusinessException("生成抽认卡失败"));
        log.info("CozeService genFlashcardsV2 response:{}", JsonUtils.toJson(response));
        return ResultUtil.success("AI生成抽认卡成功", response.getCards());
    }

    /**
     * AI资源搜索
     */
    public ResultUtil webSearch(String subtopic) {
        CozeWebSearchParam param = new CozeWebSearchParam();
        param.setSubtopic(subtopic);
        CozeRequest<CozeWebSearchParam> cozeRequest = new CozeRequest<>();
        cozeRequest.setParameters(param);
        log.info("CozeService webSearch request:{}", JsonUtils.toJson(cozeRequest));
        CozeWebSearchResponse response = Optional.ofNullable(cozeWebSearchWFProcessor.runWorkFlow(cozeRequest, CozeWebSearchResponse.class))
                .orElseThrow(() -> new BusinessException("AI资源搜索失败"));
        log.info("CozeService webSearch response:{}", JsonUtils.toJson(response));
        return ResultUtil.success("AI资源搜索成功", response.getData());
    }

    /**
     * 查询学习计划生成状态
     */
    public ResultUtil queryStudyPlanStatus(Long planId){
        // 判断planId是否存在
        Plan plan = Optional.ofNullable(planMapper.selectById(planId))
                .orElseThrow(() -> new BusinessException("计划不存在"));
                
        // 查询该计划下的所有任务
        List<CozeTask> allTasks = cozeTaskMapper.selectList(
            new LambdaQueryWrapper<CozeTask>().eq(CozeTask::getPlanId, plan.getPlanId())
        );
        
        // 如果没有任务记录，说明还在初始化中
        if (allTasks.isEmpty()) {
            throw new BusinessException("计划生成中，请稍后查看", HttpStatus.NO_CONTENT);
        }
        
        // 查询是否有正在运行的任务
        List<CozeTask> runningTasks = allTasks.stream()
            .filter(task -> CozeTaskStatus.RUNNING.getValue().equals(task.getTaskStatus()))
            .collect(Collectors.toList());
            

        if (!runningTasks.isEmpty()) {
            throw new BusinessException("计划生成中，请稍后查看", HttpStatus.NO_CONTENT);
        }
        return ResultUtil.success("计划生成成功");
    }

    public SseEmitter pushStudyPlanStatus(Long planId){
        SseEmitter sseEmitter = SseServer.createConnect(planId);
        // 进度条
        new Thread(() -> {
            while (true){
                try {
                    Thread.sleep(1000);
                    List<CozeTask> cozeTasks = cozeTaskMapper.selectList(new LambdaQueryWrapper<CozeTask>().eq(CozeTask::getPlanId, planId));
                    int total = cozeTasks.size();
                    int success = 0;
                    int fail = 0;
                    for (CozeTask cozeTask : cozeTasks) {
                        if(cozeTask.getTaskStatus().equals(CozeTaskStatus.SUCCESS.getValue())){
                            success++;
                        }else if(cozeTask.getTaskStatus().equals(CozeTaskStatus.FAIL.getValue())){
                            fail++;
                        }
                    }
                    SseServer.sendMessage(planId, String.format("计划生成中，总任务数：%d,成功：%d,失败：%d", total, success, fail));
                } catch (Exception e) {
                    log.error("SseEmitter error:{}", e.getMessage());
                    break;
                }
            }
        }).start();
        return sseEmitter;
    }


    public GenCacheVO getGenCache(Long userId) {
        String quizKey = CacheConstants.USER_GEN_QUIZ_KEY + userId;
        Map<String, com.example.aigc_education.integration.response.workflows.v2.CozeGenQuizzesResponse> quizCache = redisCache.getCacheObject(quizKey);
        String flashKey = CacheConstants.USER_GEN_FLASH_KEY + userId;
        Map<String, com.example.aigc_education.integration.response.workflows.v2.CozeGenFlashCResponse> flashCache = redisCache.getCacheObject(flashKey);
        //如果两个集合都为空，则返回null
        if (quizCache == null && flashCache == null) {
            return null;
        } else {
            return new GenCacheVO(quizCache, flashCache);
        }
    }
}
